home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
TCL1
/
TCLOPT.TXT
< prev
Wrap
Text File
|
1990-08-04
|
6KB
|
162 lines
Improvements to the THINK Class Library
=======================================
I recently helped a friend optimize his application. His two biggest
problems were slowness when resizing windows and when scrolling. He
had identified the slow methods; I came up with the following
changes to CPane.c to speed things up.
I don't guarantee that these changes are free of negative side
effects, but they dramatically increased the performance of his application
with large documents.
I'm also aware that further improvements along these lines may be
possible. Sorry, but I only have time to work on things that demand
attention right now...
I encourage you to examine the changes skeptically and let me know if
you have problems.
Doug Wyatt, 7/31/90 (CIS: 76004,2156)
======================================================================================
#1. Window changing size sends ChangeSize to all panes in window. SLOW.
Why? CalcAperture is visiting all subpanes. Since a pane's aperture
is a function of its enclosure's aperture and its frame, subpanes'
apertures only need recalculation when their enclosure's aperture
changes.
/*
CPane::CalcAperture
Improvement: Don't ask subviews to recalculate their apertures if the pane's
aperture didn't change.
*/
void CPane::CalcAperture()
{
Rect enclAperture; /* Aperture of pane's enclosure */
Rect prevAperture;
prevAperture = aperture;
/* Get enclosure's aperture */
itsEnclosure->GetAperture(&enclAperture);
EnclToFrameR(&enclAperture); /* Convert it to Frame coords */
/* Aperture is the frame restricted */
/* by the enclosure's aperture */
SectRect(&frame, &enclAperture, &aperture);
if (!EqualRect(&prevAperture, &aperture) && itsSubviews != NULL) /* dsw 7/30/90 */
itsSubviews->DoForEach(Pane_CalcAperture); /* Pass it on to subviews */
}
==================================================================================================
#2. Scrolling is slow. The problem is that Offset calls CalcAperture
for every subpane of every subpane (...) in the window, despite
the first optimization.
This, in effect, applies the same optimization to Offset, but the
implementation is slightly complicated. Offset now records whether
the pane's aperture has changed, and then Pane_EnclosureMoved
looks at this to decide whether to bother recalculating the subpane's
aperture.
/*
Pane_SimpleCalcAperture
Just like CalcAperture, except:
Say whether the aperture changed. Don't visit subviews.
Used by improved Offset().
Could be a method if you don't mind recompiling. It's just as fast
(though less readable) this way.
*/
static Boolean Pane_SimpleCalcAperture(register CPane *pane); /* prototype */
static Boolean Pane_SimpleCalcAperture(register CPane *pane)
{
Rect enclAperture; /* Aperture of pane's enclosure */
Rect prevAperture;
prevAperture = pane->aperture;
/* Get enclosure's aperture */
pane->itsEnclosure->GetAperture(&enclAperture);
pane->EnclToFrameR(&enclAperture); /* Convert it to Frame coords */
/* Aperture is the frame restricted */
/* by the enclosure's aperture */
SectRect(&pane->frame, &enclAperture, &pane->aperture);
return ( !EqualRect(&prevAperture, &pane->aperture) );
}
/******************************************************************************
Offset
Translate the location of the Pane within its enclosure
******************************************************************************/
typedef struct {
Point offset;
Boolean enclosureApertureChanged;
} OffsetInfo;
/*
* Tell a Pane that its enclosure has moved. Send Offset message
* with redraw set to FALSE, since enclosure will have already
* taken care of adding the appropriate areas to the update region.
*/
static void Pane_EnclosureMoved(
register CPane *thePane,
OffsetInfo *moveInfo)
{
/* Instead of recursing into Offset, replicate relevant code */
/* Don't need to refresh */
thePane->hOrigin -= moveInfo->offset.h; /* Change location of the pane */
thePane->vOrigin -= moveInfo->offset.v;
/* Only need to CalcAperture if its OUTERMOST MOVED enclosure's
aperture was changed. (Actually, if THIS pane's enclosure's
aperture hadn't changed, that would be reason not to
recalculate; but for simplicity, we're just covering the grossest
case of a panorama with hundreds of panes being offset during
scrolling, and most of their apertures not changing). */
if (moveInfo->enclosureApertureChanged)
Pane_SimpleCalcAperture(thePane);
if (thePane->itsSubviews)
thePane->itsSubviews->DoForEach1(Pane_EnclosureMoved, (long)moveInfo);
}
void CPane::Offset(
short hOffset, /* Pixels to offset horizontally */
short vOffset, /* Pixels to offset vertically */
Boolean redraw) /* Redraw Pane or not? */
{
OffsetInfo moveInfo;
if (redraw) {
Refresh(); /* Force redraw of area covered by */
} /* current location of pane */
hOrigin -= hOffset; /* Change location of the pane */
vOrigin -= vOffset;
moveInfo.enclosureApertureChanged = Pane_SimpleCalcAperture(this);
/* Visible portion of pane could */
/* change as a result of a shift */
/* in its location */
if (redraw) {
Refresh(); /* Redraw pane at its new location */
}
if (itsSubviews != NULL) { /* Inform subviews of the move */
moveInfo.offset.h = hOffset; /* so they can adjust their */
moveInfo.offset.v = vOffset; /* locations */
itsSubviews->DoForEach1(Pane_EnclosureMoved, (long) &moveInfo);
}
}